package br.com.nuccitec.jfera.validation.vo;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class FieldsVOValidator implements IFieldsVOValidator {
	@Override
	public <E> void validate(E originalVO, E newVO) throws FieldsVOException {
		checkCreateOnlyProperties(originalVO, newVO);
		checkReadOnlyProperties(originalVO, newVO);
	}

	<E> void checkCreateOnlyProperties(E originalVO, E newVO) throws FieldsVOException {
		List<Method> createOnlyMethods = findAnnotadOnlyMethods(originalVO.getClass(), CreateOnlyField.class);
		Object getMethodReturn;
		for (Method m : createOnlyMethods) {
			try {
				getMethodReturn = m.invoke(originalVO);
				if (getMethodReturn != null && !getMethodReturn.equals(m.invoke(newVO))) {
					throw new FieldsVOException("Operação não permitida");
				}
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	<E> void checkReadOnlyProperties(E originalVO, E newVO) throws FieldsVOException {
		List<Method> readOnlyMethods = findAnnotadOnlyMethods(originalVO.getClass(), ReadOnlyField.class);
		Object getOriginalMethodReturn;
		Object getNewMethodReturn;
		for (Method m : readOnlyMethods) {
			try {
				getOriginalMethodReturn = m.invoke(originalVO);
				getNewMethodReturn = m.invoke(newVO);
				if (getOriginalMethodReturn == null) {
					if (getNewMethodReturn != null) {
						throw new FieldsVOException("Operação não permitida");
					}
				} else if (!getOriginalMethodReturn.equals(getNewMethodReturn)) {
					throw new FieldsVOException("Operação não permitida");
				}
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	List<Method> findAnnotadOnlyMethods(Class<? extends Object> clazz, Class<? extends Annotation> annotationClass) {
		List<Method> list = new ArrayList<Method>();
		for (Method method : clazz.getMethods()) {
			if (method.isAnnotationPresent(annotationClass)) {
				list.add(method);
			}
		}
		return list;
	}
}
